package com.buydeem.share.hystrixdemo;

import com.buydeem.share.hystrixdemo.model.User;
import com.buydeem.share.hystrixdemo.service.UserService;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 请求合并
 * @author zengchao
 * @version 1.0.0
 * @ClassName App3.java
 * @Description TODO
 * @createTime 2021年04月05日 21:32:00
 */
@Slf4j
public class App3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        try {
            List<String> users = Arrays.asList("mac", "tom", "jack");
            //使用execute并不能将请求合并
            users.forEach(name ->{
                User user = new CollapserQueryCommand(name).execute();
                log.info(user.toString());
            });
            //需要使用异步的方式
            List<Future<User>> fList = users.stream().map(name -> new CollapserQueryCommand(name).queue()).collect(Collectors.toList());
            for (Future<User> userFuture : fList) {
                log.info(userFuture.get().toString());
            }

        }finally {
            context.shutdown();
        }
    }
}

/**
 * 请求合并
 */
@Slf4j
class CollapserQueryCommand extends HystrixCollapser<List<User>,User,String>{
    private final String name;

    CollapserQueryCommand(String name) {
        this.name = name;
    }

    @Override
    public String getRequestArgument() {
        return name;
    }

    @Override
    protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, String>> collapsedRequests) {
        List<String> names = new ArrayList<>();
        for (CollapsedRequest<User, String> collapsedRequest : collapsedRequests) {
            String name = collapsedRequest.getArgument();
            names.add(name);
        }
        return new BatchCommand(names);
    }

    @Override
    protected void mapResponseToRequests(List<User> batchResponse, Collection<CollapsedRequest<User, String>> collapsedRequests) {
        int count = 0;
        for (CollapsedRequest<User, String> collapsedRequest : collapsedRequests) {
            collapsedRequest.setResponse(batchResponse.get(count++));
        }
    }
}

class BatchCommand extends HystrixCommand<List<User>>{
    private final List<String> names;
    private final UserService userService = new UserService();

    BatchCommand(List<String> names) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("group_key"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("command_key")));
        this.names = names;
    }

    @Override
    protected List<User> run() throws Exception {
        return userService.queryUsers(names);
    }
}
